#include <iostream>
#include <pthread.h>
#include <sched.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/time.h>
#include "camera.hpp"
#include "image_decoder.hpp"
#include "image_process.hpp"
#include "drm_hdmi_page_filp.hpp"
#include "waitKey.hpp"
#include "record.hpp"

#define max_buffer  32                              //环形缓冲区个数

#define WIDTH_4K    3840
#define HEIGHT_4K   2160
#define WIDTH_2K    2560
#define HEIGHT_2K   1440
#define WIDTH_1K    1920
#define HEIGHT_1K   1080

#define CAMERA_WIDTH 1504                           //摄像头采集像素
#define CAMERA_HEIGHT 1504

uint32_t IMG_WIDTH = WIDTH_4K;                          //显示器像素
uint32_t IMG_HEIGHT = HEIGHT_4K;

uint32_t FIT_WIDTH = 1504;
uint32_t FIT_HEIGHT = 1504;

//采集、解码相关变量
unsigned char * buf_jpeg[max_buffer] = { NULL };    //v4l2采集的jpeg格式数据
unsigned char * buf_rgb[max_buffer] = { NULL };     //解码之后的rgb格式数据
MJpegDecoder *jpeg_decoder = NULL;                  //解码器上下文
int jpeg_byteused[max_buffer];                      //每帧jpeg格式图像使用到的字节数
Mat frame[max_buffer];                              //opencv处理用的变量格式
Mat frame_cut[max_buffer];
Mat frame_awb[max_buffer];
Scalar awb_gain(1.0,1.0,1.0);
Mat resized[max_buffer];
char file_path[50];                                 //录屏的文件路径
int64_t record_cnt;
uint32_t record_width;                              //录屏初始化的大小
uint32_t record_height;

//HDMI显示相关变量
extern int drm_hdmi_fd;
extern uint32_t hdmi_crtc_id;
extern struct drm_hdmi_device drm_hdmi_buf[2];
drmEventContext ev;		                            //翻页用
uint8_t page_cnt = 0;
uint8_t key_num = 0;                                //检测哪个按键被按下

//线程相关变量
pthread_t thread_id_capture_decoder;                //线程ID
pthread_t thread_id_img_process_1;                  //线程ID
pthread_t thread_id_img_process_2;                  //线程ID
pthread_t thread_id_img_process_3;
pthread_t thread_id_img_process_4;
pthread_t thread_id_img_process_5;
pthread_t thread_id_drm_show;                       //drm线程ID
pthread_t thread_id_key_scan;                       //按键扫描线程

//共8线程协同
sem_t sem_buf_empty;                                //缓冲区空余信号量，用于图像采集和解码
sem_t sem_process_1;                                //缓冲区数据轮转过程信号量
sem_t sem_process_2;
sem_t sem_process_3;
sem_t sem_process_4;
sem_t sem_process_5;
sem_t sem_buf_fill;                                 //缓冲区填充信号量，用于drm显示
pthread_rwlock_t rwlock_menu;

MENU menu;                                          //菜单结构体
MENU menu_cp[max_buffer];                           //菜单结构体的副本
Ptr <freetype::FreeType2> ft2;                      //字体文件

//drm显示回调函数
static void drm_page_flip_handler(int fd, uint32_t frame,
    uint32_t sec, uint32_t usec,
    void *data)
	{
    uint32_t crtc_id = *(uint32_t *)data;

    drmModePageFlip(drm_hdmi_fd, hdmi_crtc_id, drm_hdmi_buf[page_cnt].fb_id,
        DRM_MODE_PAGE_FLIP_EVENT, &hdmi_crtc_id);
    
    if(page_cnt == 0)
      page_cnt = 1;
    else 
      page_cnt = 0;
}
//采集、jpeg解码、裁剪线程函数，将jpeg转换为rgb888格式，封装为cv::Mat并裁剪为圆形
void *thread_capture_decoder(void *argv)
{
    //pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
    while (1)
    {
        for (int i = 0; i < max_buffer; i++)
        {
            sem_wait(&sem_buf_empty);

            buf_jpeg[i] = camera_capture_one(&jpeg_byteused[i]);

            mjpeg_decoder_process(jpeg_decoder,buf_jpeg[i],jpeg_byteused[i],CAMERA_WIDTH,CAMERA_HEIGHT,&buf_rgb[i]);

            frame[i] = cv::Mat(CAMERA_HEIGHT,CAMERA_WIDTH,CV_8UC3,buf_rgb[i]);

            //获取读锁
            pthread_rwlock_rdlock(&rwlock_menu);
            menu_copy(menu,&menu_cp[i]);
            pthread_rwlock_unlock(&rwlock_menu);

            sem_post(&sem_process_1);
        }   
    }
}
//图像处理流水线线程
void *thread_img_process_1(void *argv)
{
    //pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
    while (1)
    {
        for (int i = 0; i < max_buffer; i++)
        {
            sem_wait(&sem_process_1);

            //裁剪图像为720*720
            resize(frame[i],frame_cut[i],Size(720,720),0,0,INTER_AREA);

            //白平衡校准
            if(menu_cp[i].AWB == 1)
            {
                //获取写锁
                pthread_rwlock_wrlock(&rwlock_menu);
                menu.AWB = 2;//菜单显示校准成功
                pthread_rwlock_unlock(&rwlock_menu);
                awb_gain = image_gain_awb(frame_cut[i]);
            }
            //应用白平衡参数
            xphoto::applyChannelGains(frame_cut[i], frame_awb[i], awb_gain[0], awb_gain[1], awb_gain[2]);  // src和dst分离

            sem_post(&sem_process_2);
        }
        
    }
    
}
//图像处理流水线线程
void *thread_img_process_2(void *argv)
{
    //pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
    while (1)
    {
        for (int i = 0; i < max_buffer; i++)
        {
            sem_wait(&sem_process_2);

            //调整色调
            image_adjustRGBHues(frame_awb[i],menu_cp[i]);

            //锐化调整
            if(menu_cp[i].sharpness != 0)
                image_USM(frame_awb[i],menu_cp[i]);
            
            sem_post(&sem_process_3);
        }
    }
}
//图像处理流水线线程
void *thread_img_process_3(void *argv)
{
    //pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
    while (1)
    {
        for (int i = 0; i < max_buffer; i++)
        {
            sem_wait(&sem_process_3);

            //模糊度调整
            if(menu_cp[i].blur != 0)
                image_blur(frame_awb[i],menu_cp[i]);

            //图像中心放大
            if(menu_cp[i].multiple == true)
                image_zoom(frame_awb[i]);

            sem_post(&sem_process_4);
        }
    }
}
//图像处理流水线线程
void *thread_img_process_4(void *argv)
{
    //pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
    while (1)
    {
        for (int i = 0; i < max_buffer; i++)
        {
            sem_wait(&sem_process_4);

            //调节亮度，对比度
            image_brightness_contrast(frame_awb[i],menu_cp[i]);

            //边缘遮罩
            if(menu_cp[i].mask == true)
                image_circle(frame_awb[i]);

            sem_post(&sem_process_5);
        }
    }
}
//图像处理流水线线程
void *thread_img_process_5(void *argv)
{
    //pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
    while (1)
    {
        for (int i = 0; i < max_buffer; i++)
        {
            sem_wait(&sem_process_5);

            if(IMG_WIDTH == WIDTH_4K && IMG_HEIGHT == HEIGHT_4K)
                resize(frame_awb[i],resized[i],Size(1504,1504),0,0,INTER_CUBIC);
            else if(IMG_WIDTH == WIDTH_2K && IMG_HEIGHT == HEIGHT_2K)
                resize(frame_awb[i],resized[i],Size(HEIGHT_2K,HEIGHT_2K),0,0,INTER_CUBIC);
            else if(IMG_WIDTH == WIDTH_1K && IMG_HEIGHT == HEIGHT_1K)//1080*1080提前适配屏幕
            {
                resize(frame_awb[i],resized[i],Size(1080,1080),0,0,INTER_LANCZOS4);
                //适配显示器分辨率
                image_fit(resized[i],IMG_WIDTH,IMG_HEIGHT);
            }
                
            if(menu_cp[i].record == true)
            {
                record_frame(resized[i]);
                record_cnt++;
                if(record_cnt > 25000)
                {
                    record_cnt = 0;
                    record_close();
                    time_t time_now;
                    time(&time_now);
                    sprintf(file_path,"/mnt/usb/%ld.mp4",time_now);
                    if(IMG_WIDTH == WIDTH_4K && IMG_HEIGHT == HEIGHT_4K)
                        record_init(1504,1504,file_path);
                    else if(IMG_WIDTH == WIDTH_2K && IMG_HEIGHT == HEIGHT_2K)
                        record_init(HEIGHT_2K,HEIGHT_2K,file_path);
                    else if(IMG_WIDTH == WIDTH_1K && IMG_HEIGHT == HEIGHT_1K)
                        record_init(1920,1080,file_path);
                }
            }
                
            if(IMG_WIDTH == WIDTH_1K && IMG_HEIGHT == HEIGHT_1K)
            {}
            else//1080*1080之外的，后适配显示器分辨率
                image_fit(resized[i],IMG_WIDTH,IMG_HEIGHT);

            sem_post(&sem_buf_fill);
        }
    }
}

//DRM显示线程，将cv::Mat型数组转换为XRGB888格式并拷贝到drm缓冲区
void *thread_drm_show(void *argv)
{
    //pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
    while (1)
    {
        for (int i = 0; i < max_buffer; i++)
        {
            sem_wait(&sem_buf_fill);

            //添加菜单文本
            image_menu_update(resized[i],&menu_cp[i],ft2);

            //将RGB格式的图像转换为DRM兼容的XRGB格式
            image_RGB_to_XRGB(resized[i],drm_hdmi_buf[page_cnt].vaddr);
            
            drmHandleEvent(drm_hdmi_fd, &ev);

            sem_post(&sem_buf_empty);
        }
    }
}
//检测、维护按键，更改菜单参数
void *thread_key_scan(void *argv)
{
    //pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
    while(1)
    {
        //获取按键，按下返回按键编号，否则返回0，一次按下仅返回一次
        key_num = Key_scan();

        if(key_num > 0)
        {
            time_t time_now;
            time(&time_now);
            sprintf(file_path,"/mnt/usb/%ld.mp4",time_now);
            //获取写锁，更改菜单内容
            pthread_rwlock_wrlock(&rwlock_menu);
            menu.AWB = 0;//清除菜单显示的已校准
            menu.mount = 0;//清除菜单显示的挂载成功、弹出成功
            Key_process(&menu,key_num,IMG_WIDTH,IMG_HEIGHT,file_path);
            pthread_rwlock_unlock(&rwlock_menu);
        }
        
        usleep(20000);
    }
}

/*
功能：系统整体初始化
参数：无
返回值：无
*/
void sys_init()
{
    //hdmi显示器初始化
    ev.version = DRM_EVENT_CONTEXT_VERSION;
	ev.page_flip_handler = drm_page_flip_handler;
    drm_hdmi_init(&IMG_WIDTH,&IMG_HEIGHT);

    //摄像头初始化和数据流开启
    camera_init(CAMERA_WIDTH,CAMERA_HEIGHT);
    camera_streadmon();
    //jpeg解码器上下文初始化
    jpeg_decoder = mjpeg_decoder_init(CAMERA_WIDTH,CAMERA_HEIGHT);

    //按键初始化
    Key_init();

    //加载字体文件
    ft2 = freetype::createFreeType2();
    ft2->loadFontData("./ziti.ttf", 0);
    //菜单参数初始化
    menu_init(&menu);

    //初始化读写锁，设置写优先，防止写饥饿
    pthread_rwlockattr_t attr;
    pthread_rwlockattr_init(&attr);
    pthread_rwlockattr_setkind_np(&attr,PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
    pthread_rwlock_init(&rwlock_menu,&attr);
    pthread_rwlockattr_destroy(&attr);

    //初始化缓冲区空余信号量，线程共享，初始值max_buffer（缓冲区最大数量）
    sem_init(&sem_buf_empty,0,max_buffer);
    //初始化处理过程信号量，线程共享，初始值0
    sem_init(&sem_process_1,0,0);
    sem_init(&sem_process_2,0,0);
    sem_init(&sem_process_3,0,0);
    sem_init(&sem_process_4,0,0);
    sem_init(&sem_process_5,0,0);
    //初始化缓冲区填充信号量，线程共享，初始值0
    sem_init(&sem_buf_fill,0,0);

    //创建所有执行线程
    pthread_create(&thread_id_capture_decoder,NULL,thread_capture_decoder,NULL);
    pthread_create(&thread_id_img_process_1,NULL,thread_img_process_1,NULL);
    pthread_create(&thread_id_img_process_2,NULL,thread_img_process_2,NULL);
    pthread_create(&thread_id_img_process_3,NULL,thread_img_process_3,NULL);
    pthread_create(&thread_id_img_process_4,NULL,thread_img_process_4,NULL);
    pthread_create(&thread_id_img_process_5,NULL,thread_img_process_5,NULL);
    pthread_create(&thread_id_drm_show,NULL,thread_drm_show,NULL);
    pthread_create(&thread_id_key_scan,NULL,thread_key_scan,NULL);
}

/*
功能：系统整体资源释放
参数：无
返回值：无
*/
void sys_close()
{
    //主线程等待执行线程结束
    pthread_join(thread_id_capture_decoder,NULL);
    pthread_join(thread_id_img_process_1,NULL);
    pthread_join(thread_id_img_process_2,NULL);
    pthread_join(thread_id_img_process_3,NULL);
    pthread_join(thread_id_img_process_4,NULL);
    pthread_join(thread_id_img_process_5,NULL);
    pthread_join(thread_id_drm_show,NULL);
    pthread_join(thread_id_key_scan,NULL);

    //关闭摄像头数据流并释放资源
    camera_streamoff();
    camera_close();
    //释放jpeg解码器资源
    mjpeg_decoder_release(jpeg_decoder);
    //hdmi资源释放
    drm_hdmi_exit();
    //按键资源释放
    Key_close();

    //释放读写锁
    pthread_rwlock_destroy(&rwlock_menu);
    //释放信号量
    sem_destroy(&sem_buf_empty);
    sem_destroy(&sem_process_1);
    sem_destroy(&sem_process_2);
    sem_destroy(&sem_process_3);
    sem_destroy(&sem_process_4);
    sem_destroy(&sem_process_5);
    sem_destroy(&sem_buf_fill);
}

int main(int argc, char const *argv[])
{
    //系统整体初始化
    sys_init();

    //终端读取退出命令
    char buf_cmd[30];

    //循环阻塞等待终端输入命令
    while (read(STDIN_FILENO,buf_cmd,30))
    {
        //判断输入内容与命令是否相符
        if(strncmp(buf_cmd,"exit",4) == 0)
        {
            //取消所有执行线程
            pthread_cancel(thread_id_capture_decoder);
            pthread_cancel(thread_id_img_process_1);
            pthread_cancel(thread_id_img_process_2);
            pthread_cancel(thread_id_img_process_3);
            pthread_cancel(thread_id_img_process_4);
            pthread_cancel(thread_id_img_process_5);
            pthread_cancel(thread_id_drm_show);
            pthread_cancel(thread_id_key_scan);
            break;
        }
    }
    
    //系统整体资源释放
    sys_close();

    return 0;
}
